#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

typedef unsigned short  Elf32_Half;
typedef unsigned int    Elf32_Addr;
typedef unsigned int    Elf32_Off;
typedef unsigned int    Elf32_Word;
typedef int             Elf32_Sword;

typedef struct dynamic
{
	Elf32_Sword d_tag;
	union
	{
		Elf32_Sword d_val;
		Elf32_Addr  d_ptr;
	}d_un;
} Elf32_Dyn;

#define ELF32_R_SYM(x)   ((x) >> 8)
#define ELF32_R_TYPE(x)  ((x) & 0xff)

//==================

typedef struct elf32_rel
{
	Elf32_Addr  r_offset;
	Elf32_Word  r_info;
} Elf32_Rel;

//==================

typedef struct elf32_rela
{
	Elf32_Addr  r_offset;
	Elf32_Word  r_info;
	Elf32_Sword r_addend;
} Elf32_Rela;

//==================

typedef struct elf32_sym
{
	Elf32_Word   st_name;
	Elf32_Addr   st_value;
	Elf32_Word   st_size;
	Elf32_Word   st_info;
	Elf32_Word   st_other;
	Elf32_Half   st_shndx;
} Elf32_Sym;

//======================

#define EI_NIDENT  16
typedef struct elf32_hdr
{
	unsigned char e_ident[EI_NIDENT];
	Elf32_Half    e_type;
	Elf32_Half    e_machine;
	Elf32_Word    e_version;
	Elf32_Addr    e_entry;
	Elf32_Off     e_phoff;
	Elf32_Off     e_shoff;
	Elf32_Word    e_flags;
	Elf32_Half    e_ehsize;
	Elf32_Half    e_phentsize;
	Elf32_Half    e_phnum;
	Elf32_Half    e_shentsize;
	Elf32_Half    e_shnum;
	Elf32_Half    e_shstrndx;
} Elf32_Ehd;

//========================

#define PF_R  0x4
#define PF_W  0x2
#define PF_X  0x1

typedef struct elf32_phdr
{
	Elf32_Word   p_type;
	Elf32_Off    p_offset;
	Elf32_Addr   p_vaddr;
	Elf32_Addr   p_paddr;
	Elf32_Word   p_filesz;
	Elf32_Word   p_memsz;
	Elf32_Word   p_flags;
	Elf32_Word   p_align;
} Elf32_Phdr;

/* sh_type */
#define SHT_NULL	0
#define SHT_PROGBITS	1
#define SHT_SYMTAB	2
#define SHT_STRTAB	3
#define SHT_RELA	4
#define SHT_HASH	5
#define SHT_DYNAMIC	6
#define SHT_NOTE	7
#define SHT_NOBITS	8
#define SHT_REL		9
#define SHT_SHLIB	10
#define SHT_DYNSYM	11
#define SHT_NUM		12
#define SHT_LOPROC	0x70000000
#define SHT_HIPROC	0x7fffffff
#define SHT_LOUSER	0x80000000
#define SHT_HIUSER	0xffffffff

/* sh_flags */
#define SHF_WRITE	0x1
#define SHF_ALLOC	0x2
#define SHF_EXECINSTR	0x4
#define SHF_MASKPROC	0xf0000000

/* special section indexes */
#define SHN_UNDEF	0
#define SHN_LORESERVE	0xff00
#define SHN_LOPROC	0xff00
#define SHN_HIPROC	0xff1f
#define SHN_ABS		0xfff1
#define SHN_COMMON	0xfff2
#define SHN_HIRESERVE	0xffff
 
typedef struct {
  Elf32_Word	sh_name;
  Elf32_Word	sh_type;
  Elf32_Word	sh_flags;
  Elf32_Addr	sh_addr;
  Elf32_Off	sh_offset;
  Elf32_Word	sh_size;
  Elf32_Word	sh_link;
  Elf32_Word	sh_info;
  Elf32_Word	sh_addralign;
  Elf32_Word	sh_entsize;
} Elf32_Shdr;

#define	EI_MAG0		0		/* e_ident[] indexes */
#define	EI_MAG1		1
#define	EI_MAG2		2
#define	EI_MAG3		3
#define	EI_CLASS	4
#define	EI_DATA		5
#define	EI_VERSION	6
#define	EI_OSABI	7
#define	EI_PAD		8

#define	ELFMAG0		0x7f		/* EI_MAG */
#define	ELFMAG1		'E'
#define	ELFMAG2		'L'
#define	ELFMAG3		'F'
#define	ELFMAG		"\177ELF"
#define	SELFMAG		4

#define	ELFCLASSNONE	0		/* EI_CLASS */
#define	ELFCLASS32	1       
#define	ELFCLASS64	2
#define	ELFCLASSNUM	3

#define ELFDATANONE	0		/* e_ident[EI_DATA] */
#define ELFDATA2LSB	1       
#define ELFDATA2MSB	2

#define EV_NONE		0		/* e_version, EI_VERSION */
#define EV_CURRENT	1
#define EV_NUM		2

#define ELFOSABI_NONE	0
#define ELFOSABI_LINUX	3

#ifndef ELF_OSABI
#define ELF_OSABI ELFOSABI_NONE
#endif

/* Notes used in ET_CORE */
#define NT_PRSTATUS	1
#define NT_PRFPREG	2
#define NT_PRPSINFO	3
#define NT_TASKSTRUCT	4
#define NT_AUXV		6
#define NT_PRXFPREG     0x46e62b7f      /* copied from gdb5.1/include/elf/common.h */
#define NT_PPC_VMX	0x100		/* PowerPC Altivec/VMX registers */
#define NT_PPC_SPE	0x101		/* PowerPC SPE/EVR registers */
#define NT_386_TLS	0x200		/* i386 TLS slots (struct user_desc) */


/* Note header in a PT_NOTE section */
typedef struct elf32_note {
  Elf32_Word	n_namesz;	/* Name size */
  Elf32_Word	n_descsz;	/* Content size */
  Elf32_Word	n_type;		/* Content type */
} Elf32_Nhdr;

void* shname_table;


void readelf( FILE*fp, Elf32_Off start, Elf32_Word size);

int main(int argc, char* argv[])
{
	int i;
	int fd;
	FILE *fp;
	Elf32_Ehd *ehd; 
	Elf32_Phdr *phdr;
	Elf32_Shdr *shdr;

	int num, len;

	ehd = (Elf32_Ehd *) malloc (sizeof (Elf32_Ehd));

	printf("\n===============");

	fp = fopen( argv[1], "rb");
	if (fp == NULL)
	{
		printf("\nfile open failed!");
		return 1;
	}

	fseek(fp, 0, SEEK_END);
	len = ftell(fp);
	if (len < sizeof(Elf32_Ehd))
	{
		printf("\nfile is failure.");
		return 1;
	}

	// 读到ＥＬＦ文件头
	rewind(fp);
	fread(ehd, sizeof(Elf32_Ehd), 1, fp);
	if ( (ehd->e_ident[EI_MAG0] != ELFMAG0) || 
		 (ehd->e_ident[EI_MAG1] != ELFMAG1) ||
		 (ehd->e_ident[EI_MAG2] != ELFMAG2) ||
		 (ehd->e_ident[EI_MAG3] != ELFMAG3) )
	{
		printf("\n no elf file. %d %d %d %d", ehd->e_ident[EI_MAG0],
				ehd->e_ident[EI_MAG1], ehd->e_ident[EI_MAG2], 
				ehd->e_ident[EI_MAG3]);
		return 1;
	}

	if ( ehd->e_type == 1 )
		printf("\n可重定位文件");
	else if ( ehd->e_type == 2 )
		printf("\n可执行文件");
	else if ( ehd->e_type == 3 )
		printf("\n共目标文件");
	else
	{
		printf("\n file type is unknown.");
		return 1;
	}

	printf("\n目录体系结构为type: %d",ehd->e_machine);
	printf("\n入口地址：%d" , ehd->e_entry);
	printf("\nProgram Header Table offset: %d", ehd->e_phoff);
	printf("\nSection Header Table offset: %d", ehd->e_shoff);
	printf("\ne_flags for processor: %d", ehd->e_flags);
	printf("\nELF header size: %d", ehd->e_ehsize);
	printf("\n程序头表大小：%d", ehd->e_phentsize);
	printf("\n程序头表的表项数：%d", ehd->e_phnum);
	printf("\n节头部表大小：%d", ehd->e_shentsize);
	printf("\n节头部表的表项数：%d", ehd->e_shnum);
	printf("\n节头部表字串表项索引：%d", ehd->e_shstrndx);
	

	//====================================
	if (ehd->e_phnum!=0)
	{
		rewind(fp);
		fread(ehd, sizeof(Elf32_Ehd), 1, fp);
		phdr = (Elf32_Phdr *)malloc(sizeof(Elf32_Phdr));
		num= ehd->e_phnum;   len = ehd->e_phentsize;
		fseek(fp, ehd->e_phoff, SEEK_SET);
		printf("\n=================");
		printf("\n程序头部信息: %d", num);
		printf("\n=================");
		printf("\n%10s|%8s|%8s|%8s|%8s|%8s|%8s",
				"type","offset-f","vaddr","paddr",
				"size1-f","size2-r","power");
		for (i=0; i<num; i++)
		{
			printf("\n");
			fread(phdr, len, 1, fp);
			switch(phdr->p_type)
			{
			 case 0:printf("unused    |");break;
			 case 1:printf("load      |");break;
			 case 2:printf("dyn-info  |");break;
			 case 3:printf("--------  |");break;
			 case 4:printf("atta-info |");break;
			 case 5:printf("reserved  |");break;
			 case 6:printf("########  |");break;
			 default:printf("reserved |");
			}
			printf("%8x|",phdr->p_offset);
			printf("%8x|",phdr->p_vaddr);
			printf("%8x|",phdr->p_paddr);
			printf("%8x|",phdr->p_filesz);
			printf("%8x|",phdr->p_memsz);
			Elf32_Word flag1,flag2,flag3;
			flag1=phdr->p_flags&0x1;
			flag2=phdr->p_flags&0x2;
			flag3=phdr->p_flags&0x4;
			if(flag1==1)
				printf("x");
			if(flag2==2)
				printf("w");
			if(flag3==4)
				printf("r");
		}
	}

	if (ehd->e_shnum !=0)
	{
//		shdr=(Elf32_Shdr*)malloc(sizeof(Elf32_Shdr));
//		Shdr_offset=ehd->e_shoff+ehd->e_shentsize*ehd->e_shstrndx;
//		rewind(fp);
//		fseek(fp,Shdr_offset,SEEK_SET);
//		fread(shname_shdr,sizeof(struct Elf32_Shdr) , 1, fp);
//		S_offset=shname_shdr->sh_offset;
//		shname_table=malloc(shname_shdr->sh_size);
		
//		rewind(fp);
//		fseek(fp,S_offset,SEEK_SET);
//		fread(shname_table,shname_shdr->sh_size,1,fp);
		
		rewind(fp);
		fread(ehd, sizeof(Elf32_Ehd), 1, fp);
		shdr=(Elf32_Shdr *)malloc(sizeof(Elf32_Shdr));
		num= ehd->e_shnum;  len = ehd->e_shentsize;
		fseek(fp, ehd->e_shoff, SEEK_SET);

		short buf[8];
		while(num-- > 0)
		{
			fread(buf, 16, 1, fp);
			printf("\n%04x %04x %04x %04x %04x %04x %04x %04x",buf[0], buf[1], buf[2],buf[3], buf[4], buf[5], buf[6], buf[7]);
		}
		fclose(fp);
		return;


		
		printf("\n=================");
		printf("\n节头部信息: %d", num);
		printf("\n=================");
		
		printf("\n%10s|%10s|%5s|%5s|%5s|%5s|%5s|%5s|%5s|%5s",
				"name","type","flags","addr","offs",
				"size","link","info","-----","esize");
		for(i=0;i<num;i++)
		{
			printf("\n");
			fread(shdr,len,1,fp);
			printf("%10d|",shdr->sh_name);	//打印节名
			//type
			switch(shdr->sh_type)
			{
				case 0:printf("%10s|","none");break;
				case 1:printf("%10s|","prog-def");break;
				case 2:printf("%10s|","symtab");
					  /* print_Sym(shdr->sh_offset,shdr->sh_size);*/
					   break;
				case 3:printf("%10s|","strtab");break;
				case 4:printf("%10s|","==rel==");break;
				case 5:printf("%10s|","hash");break;
				case 6:printf("%10s|","dynamic");break;
				case 7:printf("%10s|","note");break;
				case 8:printf("%10s|","?????");break;
				case 9:printf("%10s|","**rel**");break;
				case 10:printf("%10s|","reserved");break;
				case 11:printf("%10s|","dynsym");
						/*print_Sym(shdr->sh_offset,shdr->sh_size);*/
											 break;
				default:printf("%10x|",shdr->sh_type);
			}

			Elf32_Word flag1,flag2,flag3;
			flag1=shdr->sh_flags&0x1;
			flag2=shdr->sh_flags&0x2;
			flag3=shdr->sh_flags&0x4;
			printf("--");
			if(flag1==1) printf("d");else printf("-");
			if(flag2==2) printf("b");else printf("-");
			if(flag3==4) printf("t");else printf("-");
			printf("|");

			printf("%5x|",shdr->sh_addr);
			printf("%5x|",shdr->sh_offset);
			printf("%5x|",shdr->sh_size);
		}
	}

	printf("\n\n\n");
	return 0;
}

void readelf( FILE*fp, Elf32_Off start, Elf32_Word size)
{
	if (fp == NULL)
		return;
}
